package com.niiwoo.civet.trade.service.local.newRefund.refundDeal.core;

import com.alibaba.fastjson.JSON;
import com.niiwoo.civet.trade.constant.TradeMqConstant;
import com.niiwoo.civet.trade.dao.entity.RefundOrder;
import com.niiwoo.civet.trade.dao.entity.RefundOrderDetail;
import com.niiwoo.civet.trade.dao.entity.RefundOrderDetailBiz;
import com.niiwoo.civet.trade.dao.mapper.RefundOrderDetailMapperExt;
import com.niiwoo.civet.trade.dao.mapper.RefundOrderMapperExt;
import com.niiwoo.civet.trade.dto.newRefund.RefundOrderDetailDTO;
import com.niiwoo.civet.trade.service.local.newRefund.notify.dto.RefundNotifyMsgDTO;
import com.niiwoo.civet.trade.service.local.newRefund.notify.enums.RefundNotifyRefundStatusEnum;
import com.niiwoo.tripod.lanmao.component.LanMaoDirectService;
import com.niiwoo.tripod.lanmao.enums.BusinessTypeEnum;
import com.niiwoo.tripod.lanmao.enums.ResponseStatusEnum;
import com.niiwoo.tripod.lanmao.enums.TransactionTypeEnum;
import com.niiwoo.tripod.lanmao.request.AsyncTransactionRequest;
import com.niiwoo.tripod.lanmao.response.AsyncTransactionResponse;
import lombok.extern.slf4j.Slf4j;

import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

@Service
@Slf4j
public class RefundToLanMaoService {

    @Autowired
    private LanMaoDirectService lanMaoDirectService;

    @Autowired
    private UnFreezeDealingService unFreezeDealingService;

    @Autowired
    private RefundOrderMapperExt refundOrderMapperExt;

    @Autowired
    private RefundOrderDetailMapperExt refundOrderDetailMapperExt;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    /**
     * 部分失败，重发明细
     * @param refundOrderDetailDTOs
     * @param batchNo
     * @param refundOrderId
     */
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void refundToLanMaoForRepeat(List<RefundOrderDetailDTO> refundOrderDetailDTOs, String batchNo, Long refundOrderId) {
        this.refundToLanMao(refundOrderDetailDTOs,batchNo,refundOrderId,true);
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void refundToLanMao(List<RefundOrderDetailDTO> refundOrderDetailDTOs, String batchNo, Long refundOrderId) {
        this.refundToLanMao(refundOrderDetailDTOs,batchNo,refundOrderId,false);
    }
    /**
     * 发起批量交易请求
     * @param refundOrderDetailDTOs
     * @param batchNo
     * @param refundOrderId
     * @param isRepeat 是否重发交易
     */
    private void refundToLanMao(List<RefundOrderDetailDTO> refundOrderDetailDTOs, String batchNo, Long refundOrderId,Boolean isRepeat) {
        try {
            AsyncTransactionRequest request = this.buildParam(refundOrderDetailDTOs, batchNo);
            log.info("存管还款接口请求参数,request=" + JSON.toJSONString(request));
            CompletableFuture<AsyncTransactionResponse> asyncTransactionResponseCompletableFuture = lanMaoDirectService.asyncTransaction(request);
            AsyncTransactionResponse asyncTransactionResponse = null;
            try{
                asyncTransactionResponse = asyncTransactionResponseCompletableFuture.get();
            } catch (InterruptedException | ExecutionException e ) {
                log.error("请求存管失败，refundOrderId={}, batchNo={}", refundOrderId, batchNo, e);
            }
            // 100001 系统异常
            if( null != asyncTransactionResponse  && !"100001".equals(asyncTransactionResponse.getErrorCode())){
                log.info("存管还款接口响应响应,resp=" + JSON.toJSONString(asyncTransactionResponse));
                // 明确知道失败需要处理
                if (!isRepeat && ResponseStatusEnum.INIT.getValue().equals(asyncTransactionResponse.getStatus())) {
                    log.info("存在还款交易接口请求失败，还款订单失败,refundOrderId={}",refundOrderId);
                    this.refundOrderHandleToFailed(refundOrderId, null, refundOrderDetailDTOs,asyncTransactionResponse.getErrorCode(),asyncTransactionResponse.getErrorMessage());
                }else if (isRepeat && ResponseStatusEnum.INIT.getValue().equals(asyncTransactionResponse.getStatus())){
                    log.info("部分明细重发失败，请人工处理,refundOrderId={}",refundOrderId);
                }
            }
        } catch (Exception e ) {
           log.error("还款请求存管后续流程失败，refundOrderId={}, batchNo={}", refundOrderId, batchNo, e);
        }
    }

    @Transactional
    public void refundOrderHandleToFailed(Long refundOrderId, RefundOrder refundOrder, List<RefundOrderDetailDTO>  refundOrderDetailDTOs,String errorCode,String errorMsg){
        RefundOrder refundOrderUpdater = new RefundOrder();
        refundOrderUpdater.setId(refundOrderId);
        refundOrderUpdater.setUnfreezeStatus(Byte.valueOf("1"));
        refundOrderUpdater.setStatus(Byte.valueOf("3"));
        refundOrderUpdater.setErrorCode(errorCode);
        refundOrderUpdater.setErrorMessage(errorMsg);
        refundOrderUpdater.setUpdateTime(new Date());
        refundOrderMapperExt.updateByPrimaryKeySelective(refundOrderUpdater);

        for (RefundOrderDetail detail : refundOrderDetailDTOs) {
            RefundOrderDetail refundOrderDetailUpdater = new RefundOrderDetail();
            refundOrderDetailUpdater.setId(detail.getId());
            refundOrderDetailUpdater.setStatus(Byte.valueOf("3"));
            refundOrderDetailMapperExt.updateByPrimaryKeySelective(refundOrderDetailUpdater);
        }

        if (null == refundOrder) {
        	refundOrder = refundOrderMapperExt.selectByPrimaryKey(refundOrderId);
        }

        // 还款通知MQ消息
    	RefundNotifyMsgDTO refundNotifyMsgDTO = new RefundNotifyMsgDTO();
    	refundNotifyMsgDTO.setRefundStatus(RefundNotifyRefundStatusEnum.REPAPYMENT_FAIL.getStatus());
		refundNotifyMsgDTO.setProjectId(refundOrder.getProjectId());
		refundNotifyMsgDTO.setRefundOrderId(refundOrder.getId());
		refundNotifyMsgDTO.setOrgRequestNo(refundOrder.getOrgRequestNo());
		refundNotifyMsgDTO.setRefundTradeSource(refundOrder.getTradeSource());
		refundNotifyMsgDTO.setFailMessage(errorMsg);
		rabbitTemplate.convertAndSend(TradeMqConstant.REFUND_NOTIFY_HANDLE_EXCHANGE,
				TradeMqConstant.REFUND_NOTIFY_HANDLE_ROUTINGKEY, refundNotifyMsgDTO);
        
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
            @Override
            public void afterCommit() {
                // 解冻通过
                unFreezeDealingService.unFreezeDeal(refundOrderId);
            }
        });
    }

    /**
     * 构建参数
     * @param refundOrderDetailDTOs
     * @param batchNo
     * @return
     */
    private AsyncTransactionRequest buildParam(List<RefundOrderDetailDTO> refundOrderDetailDTOs, String batchNo){
        AsyncTransactionRequest result = new AsyncTransactionRequest();
        result.setBatchNo(batchNo);
        List<AsyncTransactionRequest.BizDetail> bizDetails = new ArrayList<>();
        result.setBizDetails(bizDetails);
        for (RefundOrderDetailDTO refundOrderDetailDTO : refundOrderDetailDTOs) {
            AsyncTransactionRequest.BizDetail bizDetail = new AsyncTransactionRequest.BizDetail();
            bizDetails.add(bizDetail);

            bizDetail.setTradeType(TransactionTypeEnum.valueOf(refundOrderDetailDTO.getTradeType()));
            bizDetail.setProjectNo(String.valueOf(refundOrderDetailDTO.getProjectId()));
            bizDetail.setRequestNo(refundOrderDetailDTO.getDetailRequestNo());
            List<AsyncTransactionRequest.BizDetail.BusinessDetail> details = new ArrayList<>();
            bizDetail.setDetails(details);
            for (RefundOrderDetailBiz refundOrderDetailBiz : refundOrderDetailDTO.getRefundOrderDetailBizList()) {
                AsyncTransactionRequest.BizDetail.BusinessDetail businessDetail = new AsyncTransactionRequest.BizDetail.BusinessDetail();
                details.add(businessDetail);
                businessDetail.setBizType(BusinessTypeEnum.valueOf(refundOrderDetailBiz.getBizType()));
                businessDetail.setFreezeRequestNo(refundOrderDetailBiz.getFreezeRequestNo());
                businessDetail.setSourcePlatformUserNo(refundOrderDetailBiz.getSourcePlatformUserNo());
                businessDetail.setTargetPlatformUserNo(refundOrderDetailBiz.getTargetPlatformUserNo());
                businessDetail.setAmount(refundOrderDetailBiz.getAmount());
                if(null == refundOrderDetailBiz.getInterest()){
                    refundOrderDetailBiz.setInterest(BigDecimal.ZERO);
                }
                if(null == refundOrderDetailBiz.getPenaltyFee()){
                    refundOrderDetailBiz.setPenaltyFee(BigDecimal.ZERO);
                }
                businessDetail.setIncome(refundOrderDetailBiz.getInterest().add(refundOrderDetailBiz.getPenaltyFee()));
            }
        }
        return result;
    }

}
